﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ServiceModel;
using System.Xml;
using System.Net;
using System.Xml.Linq;
using System.Collections;

namespace SharePoint.Utilities.Cmdlets
{
    public class ImportContentTypeHelper
    {

        /// <summary>
        /// Function to delete all columns in the group specified
        /// </summary>
        /// <param name="destinationSiteCollectionURL"></param>
        /// <param name="contentTypeGroups"></param>
        /// <param name="command"></param>
        public static void DeleteColumns(string destinationSiteCollectionURL, string contentTypeGroups, RemoveColumnsCommand command)
        {
            // Get destination web service proxy
            WebsSoap destinationClient = ProxyHelper.WebsChannelFactory(destinationSiteCollectionURL);
            string[] groupNames = contentTypeGroups.Split(new char[] { ',' });
            try
            {
                // Get all site columns from source site
                XmlElement columns = destinationClient.GetColumns(new GetColumnsRequest(new GetColumnsRequestBody())).Body.GetColumnsResult;
                string deleteColumnText = string.Empty;
                XmlElement deleteColumn = new XmlDocument().CreateElement("Fields");
                XmlElement updateColumnResult = null;
                ImportTermStoreHelper.ShowMessage("Deleting columns ");
                ImportTermStoreHelper.ShowMessage("-------------------------------------");
                // loop through each columns
                foreach (XmlNode column in columns.ChildNodes)
                {
                    // Migrate only the site columns in perticular group
                    if (column.Attributes["Group"] != null && groupNames.Contains(column.Attributes["Group"].Value))
                    {
                        ImportTermStoreHelper.ShowMessage(column.Attributes["Name"].Value);
                        deleteColumnText = "<Fields></Fields>";
                        deleteColumn.InnerXml = "<Method ID='3'>" + column.OuterXml + "</Method>";
                        // Delete column, one by one.
                        updateColumnResult = destinationClient.UpdateColumns(new UpdateColumnsRequest(new UpdateColumnsRequestBody(null, null, deleteColumn))).Body.UpdateColumnsResult;

                    } // end of if
                } // end of foreach
            }
            catch (Exception ex)
            {
                ImportTermStoreHelper.ShowMessage("Deleting column exception ..." + ex.Message);

            }
        }

        /// <summary>
        /// Function to delete all site content types in the group
        /// </summary>
        /// <param name="destinationSiteCollectionURL"></param>
        /// <param name="contentTypeGroups"></param>
        /// <param name="command"></param>
        public static void DeleteSiteContentTypes(string destinationSiteCollectionURL, string contentTypeGroups, RemoveContentTypesCommand command)
        {
            // Get destination web service proxy
            WebsSoap destinationClient = ProxyHelper.WebsChannelFactory(destinationSiteCollectionURL);
            string[] groupNames = contentTypeGroups.Split(new char[] { ',' });
            try
            {
                // Get all site columns from source site
                XmlElement contentTypesXml = destinationClient.GetContentTypes(new GetContentTypesRequest(new GetContentTypesRequestBody())).Body.GetContentTypesResult;
                XElement contentTypes = XElement.Parse(contentTypesXml.OuterXml);
                ImportTermStoreHelper.ShowMessage("Deleting site content types ");
                ImportTermStoreHelper.ShowMessage("-------------------------------------");
                // loop through each column
                foreach (XElement contentType in contentTypes.Elements().OrderByDescending(id => id.Attribute("ID").Value))
                {
                    // Migrate only the site columns in perticular group
                    if (contentType.Attribute("Group") != null && groupNames.Contains(contentType.Attribute("Group").Value))
                    {
                        ImportTermStoreHelper.ShowMessage(contentType.Attribute("Name").Value);
                        XmlElement result = destinationClient.DeleteContentType(new DeleteContentTypeRequest(new DeleteContentTypeRequestBody(contentType.Attribute("ID").Value))).Body.DeleteContentTypeResult;
                    } // end of if
                } // end of foreach
            }
            catch (Exception ex)
            {
                ImportTermStoreHelper.ShowMessage("Deleting content types exception ..." + ex.Message);
            }

        }

        /// <summary>
        /// Function to Migrate Site Columns from once site to another 
        /// </summary>
        /// <param name="sourceSiteCollectionURL"></param>
        /// <param name="destinationSiteCollectionURL"></param>
        /// <param name="columnGroupNames"></param>
        
        public static string MigrateSiteColumns(string sourceSiteCollectionURL, string destinationSiteCollectionURL, string columnGroupNames)
        {
            String infoMessages = string.Empty;
            // Get source web sevice proxy
            WebsSoap sourceClient = ProxyHelper.WebsChannelFactory(sourceSiteCollectionURL);
            string[] groupNames = columnGroupNames.Split(new char[] { ',' });

            //ServiceReference1.WebsSoapClient source = new ServiceReference1.WebsSoapClient();
            // Get destination web service proxy
            WebsSoap destinationClient = ProxyHelper.WebsChannelFactory(destinationSiteCollectionURL);

            try
            {
                // Get all site columns from source site
                XmlElement columns = sourceClient.GetColumns(new GetColumnsRequest()).Body.GetColumnsResult;
                string newColumnText = string.Empty;
                XmlElement newColumn = null;
                XmlElement updateColumnResult = null;
                string message = string.Empty;
                ImportTermStoreHelper.ShowMessage("Migrating site columns ");
                infoMessages += "<br/>Migrating site columns ";
                //Console.WriteLine("Migrating site columns ");
                ImportTermStoreHelper.ShowMessage("-------------------------------------");
                infoMessages += "<br/>-------------------------------------";
                string termSetId = string.Empty;
                // loop through each column
                foreach (XmlNode column in columns.ChildNodes)
                {
                    // Migrate only the site columns in perticular group
                    if (column.Attributes["Group"] != null && groupNames.Contains(column.Attributes["Group"].Value))
                    {
                        message = column.Attributes["Name"].Value;
                        //Console.WriteLine(column.Attributes["Name"].Value);

                        // remove version tag while creating the column
                        if (column.Attributes["Version"] != null)
                        {
                            column.Attributes.Remove(column.Attributes["Version"]);
                        }
                        // Remove linkage to term store for metadata fields
                        if (column.Attributes["Type"].Value.Contains("TaxonomyFieldType"))
                        {
                            // get termset id to update it, after creating
                            termSetId = column.FirstChild.NextSibling.ChildNodes[0].ChildNodes[2].ChildNodes[1].InnerText;
                            column.RemoveChild(column.FirstChild);
                            column.RemoveChild(column.FirstChild);
                        }

                        newColumn = new XmlDocument().CreateElement("Fields");
                        newColumn.InnerXml = "<Method ID='1'>" + column.OuterXml + "</Method>";
                        // Create new column. Each column is getting created with seperate update command as creating all columns in single update command is not working.
                        updateColumnResult = destinationClient.UpdateColumns(new UpdateColumnsRequest(new UpdateColumnsRequestBody(newColumn, null, null))).Body.UpdateColumnsResult;
                        // Check for the result, the result contains the field updated. If the update is not successful, the result will not have Field.
                        if (updateColumnResult.InnerXml.Contains("<Field"))
                        {
                            // Console.WriteLine(" Successful. **");
                            ImportTermStoreHelper.ShowMessage(message + " Successful. **");
                            infoMessages += "<br/>" + message + " Successful. **";
                        }
                        else
                        {
                            //Console.WriteLine(" Unsuccessful. ---");
                            ImportTermStoreHelper.ShowMessage(message + " Unsuccessful. ---");
                            infoMessages += "<br/>" + message + " Unsuccessful. **";
                        }
                        // If it is a taxonomy field update the term set id with the original id
                        if (column.Attributes["Type"].Value.Contains("TaxonomyFieldType"))
                        {
                            newColumn = new XmlDocument().CreateElement("Fields");
                            XmlNode fields = updateColumnResult.ChildNodes[0].ChildNodes[0].ChildNodes[1];
                            fields.ChildNodes[0].ChildNodes[0].ChildNodes[2].ChildNodes[1].InnerXml = termSetId;
                            newColumn.InnerXml = "<Method ID='1'>" + fields.OuterXml + "</Method>";
                            updateColumnResult = destinationClient.UpdateColumns(new UpdateColumnsRequest(new UpdateColumnsRequestBody(null, newColumn, null))).Body.UpdateColumnsResult;
                            // Check for the result, the result contains the field updated. If the update is not successful, the result will not have Field.
                            if (updateColumnResult.InnerXml.Contains("<Field"))
                            {
                                // Console.WriteLine(" Successful. **");
                                ImportTermStoreHelper.ShowMessage(message + " Taxonomy Update Successful. **");
                                infoMessages += "<br/>" + message + " Taxonomy Update Successful. **";
                            }
                            else
                            {
                                //Console.WriteLine(" Unsuccessful. ---");
                                ImportTermStoreHelper.ShowMessage(message + " Taxonomy Update Unsuccessful. ---");
                                infoMessages += "<br/>" + message + " Taxonomy Update Unsuccessful. ---";
                            }
                        }

                    } // end of if
                } // end of foreach
            }
            catch (Exception ex)
            {
                ImportTermStoreHelper.ShowMessage("Migrating column exception ..." + ex.Message);
                infoMessages += "<br/>" + "Migrating column exception ..." + ex.Message;
            }
            return infoMessages;
        }

        /// <summary>
        /// Function to migrate site content types from source site to destination
        /// </summary>
        /// <param name="sourceSiteCollectionURL"></param>
        /// <param name="destinationSiteCollectionURL"></param>
        /// <param name="contentTypeGroupNames"></param>
        
        public static string MigrateSiteContentTypes(string sourceSiteCollectionURL, string destinationSiteCollectionURL, string contentTypeGroupNames)
        {
            string infoMessages = string.Empty;
            // Get source web sevice proxy
            WebsSoap sourceClient = ProxyHelper.WebsChannelFactory(sourceSiteCollectionURL);
            // Get destination web service proxy
            WebsSoap destinationClient = ProxyHelper.WebsChannelFactory(destinationSiteCollectionURL);
            string[] groupNames = contentTypeGroupNames.Split(new char[] { ',' });
            // Id maps
            Hashtable IdMapTable = new Hashtable();
            XmlElement newFields = new XmlDocument().CreateElement("Fields");
            XmlElement updateContentTypeResult = null;
            try
            {
                // Get all site content types from source site
                XmlElement contentTypes = sourceClient.GetContentTypes(new GetContentTypesRequest(new GetContentTypesRequestBody())).Body.GetContentTypesResult;
                XmlElement contentTypeDetail = null;
                string parentId = string.Empty;
                string newContentTypeId = string.Empty;
                string newFieldText = string.Empty;
                ImportTermStoreHelper.ShowMessage("Migrating content types ");
                ImportTermStoreHelper.ShowMessage("-------------------------------------");
                infoMessages += "Migrating content types <br/> -------------------------------------<br/>";
                string message = string.Empty;
                // loop through each column
                foreach (XElement contentType in XElement.Parse(contentTypes.OuterXml).Elements().OrderBy(id => id.Attribute("ID").Value))
                {
                    // Migrate only the site columns in perticular group
                    if (contentType.Attribute("Group") != null && groupNames.Contains(contentType.Attribute("Group").Value))
                    {
                        ImportTermStoreHelper.ShowMessage(contentType.Attribute("Name").Value + "  #####################################");
                        infoMessages += contentType.Attribute("Name").Value + "  #####################################<br/>";
                        // Get content type details
                        contentTypeDetail = sourceClient.GetContentType(new GetContentTypeRequest(new GetContentTypeRequestBody(contentType.Attribute("ID").Value))).Body.GetContentTypeResult;
                        parentId = contentType.Attribute("ID").Value;
                        parentId = parentId.Substring(0, parentId.Length - 32);
                        // check if parentId = Id + "00" + hexadecimal value
                        if (parentId.Substring(parentId.Length - 2) == "00")
                        {
                            parentId = parentId.Substring(0, parentId.Length - 2);
                        }
                        else // parentID = Id + 2 digit number
                            parentId = contentType.Attribute("ID").Value.Substring(0, contentType.Attribute("ID").Value.Length - 2);

                        // Get new value from hash table.
                        // Id of the content type created may be different from the the source site
                        if (IdMapTable[parentId] != null)
                            parentId = IdMapTable[parentId].ToString();

                        newFields.InnerXml = contentTypeDetail.FirstChild.NextSibling.InnerXml;
                        try
                        {
                            newContentTypeId = destinationClient.CreateContentType(new CreateContentTypeRequest(new CreateContentTypeRequestBody(contentType.Attribute("Name").Value, parentId, newFields, contentTypeDetail))).Body.CreateContentTypeResult;
                        }
                        catch (Exception ex)
                        {
                            ImportTermStoreHelper.ShowMessage(" Unsuccessful. ---");
                            infoMessages += " Unsuccessful. ---<br/>";
                            continue;
                        }
                        IdMapTable.Add(contentType.Attribute("ID").Value, newContentTypeId);
                        //Update content type with new fields. Content type gets created only with columns inheriting from its parent. 
                        foreach (XElement field in XElement.Parse(contentTypeDetail.FirstChild.NextSibling.OuterXml).Elements())
                        {
                            if (field.Attribute("FromBaseType") == null || field.Attribute("FromBaseType").Value.ToUpper().Equals("FALSE"))
                            {
                                message = field.Attribute("Name").Value;
                                newFields.InnerXml = "<Method ID='1'>" + field.ToString() + "</Method>";
                                try
                                {
                                    // Create new column. Each column is getting created with seperate update command as creating all columns in single update command is not working.
                                    updateContentTypeResult = destinationClient.UpdateContentType(new UpdateContentTypeRequest(new UpdateContentTypeRequestBody(newContentTypeId, contentTypeDetail, newFields, null, null))).Body.UpdateContentTypeResult;
                                }
                                catch (Exception ex)
                                {
                                    ImportTermStoreHelper.ShowMessage(message + " Unsuccessful. ---   " + ex.Message);
                                    infoMessages += message + " Unsuccessful. ---   " + ex.Message + "<br/>";
                                    continue;
                                }
                                // Check for the result, the result contains the field updated. If the update is not successful, the result will not have Field.
                                if (updateContentTypeResult.OuterXml.Contains("<Field"))
                                {
                                    ImportTermStoreHelper.ShowMessage(message + " Successful. **");
                                    infoMessages += message + " Successful. **</br>";
                                }
                                else
                                {
                                    ImportTermStoreHelper.ShowMessage(message + " Unsuccessful. ---");
                                    infoMessages += message + " Unsuccessful. ---</br>";
                                }
                            }
                        } // End foreach of fields                      

                    } // end if "belongs to a group"
                } // end of foreach
            }
            catch (Exception ex)
            {
                ImportTermStoreHelper.ShowMessage("Migrating content type exception ..." + ex.Message);
                infoMessages += "Migrating content type exception ..." + ex.Message + "</br>";
            }
            return infoMessages;
        }
    }
}
